﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using BrainTechLLC.ThreadSafeObjects;
using System.Runtime.Serialization;
using System.IO;
using System.Xml.Serialization;
using System.Diagnostics;

namespace BrainTechLLC
{
    /// <summary>
    /// Temporary (in-memory) structure to store a collection of usernames(logins) and passwords
    /// </summary>
    [Serializable]
    [DataContract]
    public class UsernamesPasswords : ThreadSafeLookup<string, UsernamePassword> 
    {        
        [field: NonSerialized]
        public static event EventHandler<ObjectEventArgs<UsernamePassword>> EnterGame;

        [field: NonSerialized]
        public static event EventHandler<ObjectEventArgs<UsernamePassword>> LeaveGame;

        [NonSerialized]
        public static ThreadSafeCounter UniqueIdCounter = new ThreadSafeCounter(1);

        [NonSerialized]
        public static ThreadSafeLookup<long, UsernamePassword> LoginLookup = new ThreadSafeLookup<long, UsernamePassword>();

        [NonSerialized]
        public static UsernamesPasswords Instance;

        [NonSerialized]
        public static object _lockObject = new object();

        public UsernamesPasswords() : base(StringComparer.OrdinalIgnoreCase) { }

        public static void OnEnterGame(UsernamePassword u)
        {
            if (EnterGame != null)
                EnterGame(u, new ObjectEventArgs<UsernamePassword>(u));
        }

        public static void OnLeaveGame(UsernamePassword u)
        {
            if (LeaveGame != null)
                LeaveGame(u, new ObjectEventArgs<UsernamePassword>(u));
        }

        // Note - id is the unique id assigned when registered using CheckUniqueIdRegistration
        public UsernamePassword FindEntryByUniqueId(long id)
        {
            return LoginLookup[id];
        }

        public void CheckUniqueIdRegistration(UsernamePassword usernamePassword)
        {
            // Register with a unique Id if not already assigned
            if (usernamePassword.UniqueId == 0)
            {
                lock (_lockObject)
                {
                    if (usernamePassword.UniqueId == 0)
                    {
                        usernamePassword.UniqueId = UniqueIdCounter.Increment();
                        LoginLookup.Add(usernamePassword.UniqueId, usernamePassword);
                    }
                }
            }
        }

        public void AssociateIDWithLogin(UsernamePassword usernamePassword, long id)
        {
            CheckUniqueIdRegistration(usernamePassword);

            if (usernamePassword.AssociatedIDs == null)
                usernamePassword.AssociatedIDs = new ThreadSafeListValues<long>();

            usernamePassword.AssociatedIDs.Add(id);
            
            Save();
        }

        public bool CheckUniqueAndAdd(UsernamePassword usernamePassword)
        {
            UsernamePassword found = this[usernamePassword.UserName];

            if (found == null)
            {
                lock (_lockObject)
                {
                    found = this[usernamePassword.UserName];
                    if (found == null)
                    {
                        Add(usernamePassword.UserName, usernamePassword);
                        Save();
                        return true;
                    }
                }
            }
            return false;
        }

        public UsernamePassword DoLogin(UsernamePassword usernamePassword)
        {
            UsernamePassword found = this[usernamePassword.UserName];
            
            if (found == null)
            {
                return null;
            }

            if (found.Password.Equals(usernamePassword.Password, StringComparison.Ordinal))
                return found;

            return null;
        }

        
        [NonSerialized, XmlIgnore]
        public static string SavePath = "C:\\UsernamesAndPasswords.dat";

        public static void Save()
        {
#if NO_SILVERLIGHT
            try
            {
                File.WriteAllBytes(SavePath, Instance.SerializeToCompressedBinary());
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                Console.WriteLine(ex.ToString());
            }
#endif
        }

        public static void Load()
        {
#if NO_SILVERLIGHT
            if (File.Exists(SavePath))
            {
                Instance = File.ReadAllBytes(SavePath).DeserializeFromCompressedBinary() as UsernamesPasswords;
                if (Instance == null)
                    Instance = new UsernamesPasswords();
            }
            else
            {
                Instance = new UsernamesPasswords();
            }
#else
            Instance = new UsernamesPasswords();
#endif
        }
    }
}
